﻿using Application.Permissions.Interfaces;
using Domain.Permissions.ValueObjects;
using Infrastructure.Files;
using System.Collections.Immutable;

namespace Infrastructure.Services.Permissions
{
    public sealed class PermissionCache: IPermissionCache
    {
        private volatile ImmutableDictionary<string, IReadOnlyList<Permission>> _permissionDict
            = ImmutableDictionary<string, IReadOnlyList<Permission>>.Empty;

        private string _permissionsDirectory;

        private readonly SemaphoreSlim _reloadLock = new(1, 1);

        public PermissionCache(string permissionsDirectory)
        {
            _permissionsDirectory = permissionsDirectory ?? throw new ArgumentNullException(nameof(permissionsDirectory));
            Reload(); // 同步初始化
        }

        public IReadOnlyDictionary<string, IReadOnlyList<Permission>> PermissionDict => _permissionDict;

        private volatile ImmutableDictionary<string, Permission> _signDict = ImmutableDictionary<string, Permission>.Empty;
        public IReadOnlyDictionary<string, Permission> SignDict => _signDict;

        public async Task ReloadAsync()
        {
            await _reloadLock.WaitAsync().ConfigureAwait(false);
            try
            {
                await ReloadCoreAsync().ConfigureAwait(false);
            }
            finally
            {
                _reloadLock.Release();
            }
        }

        public void Reload()
        {
            _reloadLock.Wait();
            try
            {
                var permissions = PermissionLoader.LoadFromDirectory(_permissionsDirectory);
                var newDict = permissions.ToImmutableDictionary(
                    p => p.Key,
                    p => p.Value,
                    StringComparer.OrdinalIgnoreCase);
                _signDict = newDict.SelectMany(p => p.Value)
                .ToImmutableDictionary(k => k.PermissionSign,v => v);
                _permissionDict = newDict;
            }
            finally
            {
                _reloadLock.Release();
            }
        }

        private async Task ReloadCoreAsync()
        {
            var permissions = await Task.Run(() => PermissionLoader.LoadFromDirectory(_permissionsDirectory))
                                       .ConfigureAwait(false);
            var newDict = permissions.ToImmutableDictionary(
                p => p.Key,
                p => p.Value,
                StringComparer.OrdinalIgnoreCase);
            _signDict = newDict.SelectMany(p => p.Value)
                .ToImmutableDictionary(k => k.PermissionSign, v => v);
            _permissionDict = newDict;
        }
    }
}